/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package csp;

import java.util.AbstractList;
import java.util.ArrayList;
import java.util.List;

/**
 *
 * @author Pablo
 */
public class ForwardChecking extends AlgortimoCSP{

    @Override
    public boolean resolver(CSP problema) {
        if(this.heuValor instanceof VMR){
        VMR valorAux= (VMR) this.heuValor;
        valorAux.setVerificador((ExpertoRestriccionesAntena)problema.getVerificadorRestricciones());
       }
       
        this.verificadorRestricciones = problema.getVerificadorRestricciones();
        this.medidasRendimiento.inicializarRuntime();
        boolean resultadoBusqueda=forwardChecking(problema);
        this.medidasRendimiento.finalizarRuntime();
        return resultadoBusqueda;
    }
    public ForwardChecking(HeuristicaValor heuValor, HeuristicaVariable heuVar){
        this.heuValor = heuValor;
        this.heuVar = heuVar;
        this.medidasRendimiento = new Rendimiento();
    }
    private boolean forwardChecking(CSP problema){
        this.medidasRendimiento.incRecursiones();
         if (problema.getVariablesNoAsignadas() == 0) {
           // return verificadorRestricciones.factible(problema);
            return true;
        } else {
            Variable variableActual = heuVar.getNextVariable(problema); //Heuristica selecciona variable
            if (variableActual != null) {
                List<Valor> valoresPosibles = variableActual.getValoresPosibles();
                List<Valor> auxValoresOrdenados = new ArrayList<Valor>(heuValor.ordenarValores(valoresPosibles,variableActual, problema.getDominio().size()));

                for (Valor valorAasignar : auxValoresOrdenados) {

                    variableActual.setAsignado(valorAasignar);
                     this.medidasRendimiento.incBackTracks();
                    //verificar si hace falta al debuggear
                    //problema.getVariables().get(problema.variablePorAsignar).setAsignado(valorAasignar);
                    if (verificadorRestricciones.factible(problema)) {

                        //Se remueve el valor asignado del dominio del resto de las variables
                        for (Variable var : problema.getVariables()) {
                           // if(var.getAsignado() == null){
                            var.getValoresPosibles().remove(valorAasignar);
                            //}
                        }
                        if (comprobarHaciaAdelante(variableActual, problema)){
                            if (this.forwardChecking(problema)) {
                                return true;
                            } else {
                           //devuelve los valores quitados a los dominios
                            for (Variable var : problema.getVariables()) {
                            //if(var.getAsignado() == null){
                            var.getValoresPosibles().add(valorAasignar);
                            //}
                        }
                        }

                        } else {
                           //devuelve los valores quitados a los dominios
                            for (Variable var : problema.getVariables()) {
                            //if(var.getAsignado() == null){
                            var.getValoresPosibles().add(valorAasignar);
                            //}
                        }
                        }
                    }
                }
               variableActual.setAsignado(null);
              
               return false;
            }
            return false;
        }
    }

    private boolean comprobarHaciaAdelante(Variable variableActual, CSP problema) {
        UbicacionAntena aux;
        aux = (UbicacionAntena) variableActual;
        

        //elimina los valores del dominio de las variables visibles prohibidos
        for (Variable visible : aux.getVisibles()) {
            if (visible.getAsignado() == null){
            List<Valor> auxValoresPos = new ArrayList<Valor>(visible.getValoresPosibles());
            for (Valor valorAprobar : auxValoresPos) {
                visible.setAsignado(valorAprobar);
                if (!(verificadorRestricciones.factible(problema))) {
                    visible.getValoresPosibles().remove(valorAprobar);  //ATENCION, NO SE PUEDE BORRAR VALORES DE UN ARREGLO MIENTRAS SE RECORRE
                }
            }
                visible.setAsignado(null);
            }
        }
        //elimina los valores del dominio de las variables consecutivas prohibidas
        for (Variable consecutiva : aux.getConsecutivas()) {
            if(consecutiva.getAsignado() == null){
             List<Valor> auxValoresPos = new ArrayList<Valor>(consecutiva.getValoresPosibles());
                for (Valor valorAprobar : auxValoresPos) {
                consecutiva.setAsignado(valorAprobar);
                if (!(verificadorRestricciones.factible(problema))) {
                    consecutiva.getValoresPosibles().remove(valorAprobar);
                }
                }
                consecutiva.setAsignado(null);
            }
        }
        //comprueba si el dominio de alguna de las variables visibles es vacio
        for (Variable visible : aux.getVisibles()) {
            if (visible.getValoresPosibles().isEmpty() && problema.getVariablesNoAsignadas() != 0) {
                return false;
            }
        }
        return true;
    }

}
